/*
 * mysql_lib.c
 *
 *  Created on: 2011-6-26
 *      Author: vyouzhi
 */

#include <my_global.h>
#include <my_sys.h>
#include <mysql.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <malloc.h>

#include "mysql_lib.h"
#include "conf_lib.h"
#include "mem_lib.h"
#include "log_lib.h"
#include "error_lib.h"
#include "time_lib.h"

int free_pools = 0;

SQL_CONN *pool_create(void){
	SQL_CONN *sqc;

	sqc = (SQL_CONN *)calloc(1, sizeof(SQL_CONN));
	pthread_mutex_init(&sqc->lock, NULL);
	sqc->myconn = init_mysql();
	sqc->iam = 0;
	return sqc;
}

void pool_link(void){
    SQL_CONN *sqc;

    sqc = pool_create();
    sqc->next = free_sql_conn;
    free_sql_conn = sqc;
    free_pools++;
}

void pool_init(void){
	int i, pool_num ;
		
	pool_num = atoi(conf_get("mysql_pool"));

	if(pool_num < 1) exit(-1);
	free_sql_conn = NULL;
	pthread_mutex_init(&freelist_lock, NULL);

	for(i=0; i<pool_num; i++){
        pool_link();
	}
	use_sql_conn = free_sql_conn;	
}

SQL_CONN *pool_pop(void){
	SQL_CONN *sqc;
	
	pthread_mutex_lock(&freelist_lock);

    sqc = use_sql_conn;

    for(;sqc && sqc->iam != 0; sqc=sqc->next);

    if(NULL == sqc) {
        sqc = free_sql_conn;        
    }

	if(NULL != sqc){
        sqc->iam = 1;
		use_sql_conn = sqc->next;

		if(NULL == use_sql_conn){
			use_sql_conn = free_sql_conn;
		}
	}
    free_pools--;
	pthread_mutex_unlock(&freelist_lock);
    if(free_pools < 2){
        d_log("mysql free pools no enough! \n");
    }
	return sqc;
}

void pool_free(SQL_CONN *sqc_free){
    /*SQL_CONN *free_p, *tmp_p;

    pthread_mutex_lock(&freelist_lock);*/
    
    /*free_p = sqc_free;
    tmp_p = sqc_free->next;
    sqc_free = tmp_p;*/
    free_pools--;

    close_mysql(sqc_free->myconn);
    free(sqc_free);
    sqc_free = NULL;
    printf("free one mysql\n");
    /*pthread_mutex_unlock(&freelist_lock);*/
}

SQL_CONN *connect_sql(void){
	SQL_CONN *sqc;

	sqc = pool_pop();
	if(sqc == NULL){
		d_log("mysql pool pop  error\n");
		exit(-1);
	}
	
	if(sqc->myconn != NULL) return sqc;
	else {
		d_log("mysql connect error\n");
		return NULL;
	}
}

MYSQL *init_mysql(void){
	MYSQL *conn;
	char *mysql_host, *mysql_user, *mysql_pwd, *mysql_db, *mysql_char;
    char mysql_sock[] = "/tmp/mysql.sock";
	char utf8_set[] = "set names 'utf8'";
	int time_out = 120;
	#if MYSQL_VERSION_ID >= 50013
    	my_bool reconnect;
    #endif

	mysql_host = conf_get("mysql_host");
	mysql_user = conf_get("mysql_user");
	mysql_pwd = conf_get("mysql_pwd");
	mysql_db = conf_get("mysql_db");
	mysql_char = conf_get("mysql_char");
	
	my_init();

	mysql_thread_safe();
	conn = mysql_init(NULL);
	mysql_library_init(0, NULL, NULL);

	if(conn == NULL){
	        printf("error-- mysql init\n");
	    	exit(-1);
	}

	mysql_options(conn, MYSQL_SET_CHARSET_NAME, "utf8");
	mysql_options(conn, MYSQL_OPT_CONNECT_TIMEOUT, &time_out);

	#if MYSQL_VERSION_ID >= 50013
		reconnect = 1;
		if (mysql_options(conn, MYSQL_OPT_RECONNECT, &reconnect) != 0) {
			d_log("can't reconnect");
		}
	#endif

	if (!(mysql_real_connect(conn, mysql_host, mysql_user, mysql_pwd, mysql_db, 0, mysql_sock, 0))) {		
		printf("error mysql connect, error :%s\n", mysql_error(conn));
		close_mysql(conn);
        exit(-1);
		/*return NULL;*/
	}
	/*
	if (!mysql_set_character_set(conn, mysql_char)){
		printf("error New client character set: %s\n", mysql_character_set_name(conn));
		free(conn);
	}*/
	
	if(-1 == mysql_real_query(conn, utf8_set, strlen(utf8_set))){
		printf("error character set");
		close_mysql(conn);
		exit(-1);
	}

	return conn;
}

int query_mysql(const char *sub, MYSQL *q_conn){
	int len;
	/*char *log_sql;*/
	len = strlen(sub);
	/* reconnect 
	mysql_ping(q_conn); */
	if (mysql_real_query(q_conn, sub, len) != 0) {
		d_log(sub);
        d_log(mysql_error(q_conn));
		/*free(log_sql);*/
		error_store(ERROR_QUERY);
		/*close_mysql(q_conn);*/
		return (-1);
	}

	return (0);
}

void commit_mysql(MYSQL *c_conn){
	mysql_commit(c_conn);
}

long set_mysql(const char *sub, SQL_CONN *s_conn){
	my_ulonglong lastid;
	
	pthread_mutex_lock(&s_conn->lock);
	if(-1 == query_mysql(sub, s_conn->myconn)){
        s_conn->iam = 0;
        free_pools++;
		pthread_mutex_unlock(&s_conn->lock);
	 	return (-1);
	}
	lastid = mysql_insert_id(s_conn->myconn);	
	commit_mysql(s_conn->myconn);
    s_conn->iam = 0;
    free_pools++;
	pthread_mutex_unlock(&s_conn->lock);

	return (long)lastid;
}

char *escape_mysql(const char *sub, MYSQL *e_conn){
	char *sqlescape;
	int len = 0;

	len = strlen(sub);
	sqlescape = (char *)calloc(len+20, sizeof(char));
	mysql_real_escape_string(e_conn, sqlescape, sub, len);
	return sqlescape;
}

int list_table(const char *ctable, MYSQL *l_conn){

	MYSQL_RES *res ;
	MYSQL_ROW row;

	res = mysql_list_tables(l_conn, ctable);
	row = mysql_fetch_row(res);

	mysql_field_seek(res, 0);	
	mysql_free_result(res);

	if(row == NULL ){
		return -1;
	}
	else if(row){
	      /*The table exists 
		while(row){
                  printf("%s", row[0]);
	        }  */
		return 0; 
	}
	else{
		return -1;
	}
}

char *simple_mysql(const char *sub, MYSQL *si_conn){
	char *val = NULL;
	MYSQL_RES *res;
	MYSQL_ROW row;

	if(-1 == mysql_query(si_conn, sub)) return NULL;
	res = mysql_use_result(si_conn);

	if (res == NULL){
		if((row = mysql_fetch_row(res)) != NULL){
			val = row[0];
		}
	}

	return val;
}

DICT_LINK *get_mysql(const char *sub, int type, SQL_CONN *s_conn){
	unsigned int num_fields;
	MYSQL_ROW row;
	MYSQL_RES *res;
	MYSQL_FIELD *field;
	MYSQL *g_conn;

	FieldName *fn_head;
	DICT_LINK *dict_link_head, *dict_link_run, *dict_link_list;

	if(pthread_mutex_lock(&s_conn->lock) !=0 ) d_log("can't get lock\n");
	g_conn = s_conn->myconn;

	if( -1 == query_mysql(sub, g_conn)){
        s_conn->iam = 0;
        free_pools++;
		if(-1 == pthread_mutex_unlock(&s_conn->lock)){
			d_log(" unlock error !\n");
		} 
		return NULL; 
	}

	res = mysql_use_result(g_conn);
	/*pthread_mutex_unlock(&s_conn->lock);*/
	if (res == NULL){
        /*mysql_field_seek(res, 0);
		mysql_free_result(res);*/
        s_conn->iam = 0;
        free_pools++;
        pthread_mutex_unlock(&s_conn->lock);
		d_log("error mysql_use_result unlock\n");
		return NULL;
	}
	num_fields = mysql_num_fields(res);

	fn_head = field_init();
	while((field = mysql_fetch_field(res)) != NULL ){
		field_add(&fn_head, field->name, type);
	}

	mysql_field_seek(res,0);
	dict_link_head = dict_init();
	dict_link_list = dict_link_head;

	while ((row = mysql_fetch_row(res)) != NULL){
		dict_link_run = (DICT_LINK *)calloc(1, sizeof(DICT_LINK));
		dict_link_run->da = dict_add(fn_head, row, num_fields);
		dict_link_run->next = NULL;
		/*dict_link_head = dict_link_run;*/
		dict_link_list->next = dict_link_run;
		dict_link_list = dict_link_run;
	}

	mysql_field_seek(res, 0);	
	mysql_free_result(res);

	field_free(fn_head);
    s_conn->iam = 0;
    free_pools++;
    
    pthread_mutex_unlock(&s_conn->lock);

	return dict_link_head;
}

void close_mysql(MYSQL *c_conn){
	/* close connection 
	mysql_thread_end();*/

	mysql_close(c_conn);
	/*mysql_library_end();*/

}

/* vim: set ts=4 sw=4: */
